
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Xml.Serialization;


namespace Policy_server
{
    class MessangerServer
    {
        private TcpListener listener;
        private int Count_client_current;
        private int Count_client_real;
        private List<MessengerConnection> clients; //список подключеных клиентов

        private string[] maps;
        private PacketMap[] packetmaps;
        

        //конструктор
        public MessangerServer()
        {
            clients = new List<MessengerConnection>();
            Count_client_current = 0;
            Count_client_real = 0;

            maps = Directory.GetFiles(Environment.CurrentDirectory, "*.tnk");
            packetmaps = new PacketMap[maps.Length];
            int i = 0;
            foreach (string fname in maps)
            {
                using (StreamReader sr = new StreamReader(fname))
                {
                    String line;
                    line = sr.ReadLine();
                    process_map_string(line, i++);
                }
            }
            
        }

        public void Start()//прослушивание
        {
            listener = new TcpListener(IPAddress.Any, 4530);
            listener.Start();
            listener.BeginAcceptTcpClient(OnAcceptTcpClient, null);//прослушивание попыток входящих подключений
        }

        public void OnAcceptTcpClient(IAsyncResult ar)
        {
          //ожидание следующего запроса в другом потоке, затем обрабатываем текущий запрос
            listener.BeginAcceptTcpClient(OnAcceptTcpClient, null);
            try
            {
                Count_client_current++;
                Count_client_real++;
                TcpClient client = listener.EndAcceptTcpClient(ar);// принимаем входящее подключение и создаем новый TcpClient для связи в удаленным узлом

                Console.WriteLine("Клиент #" + Count_client_real.ToString() + " подсоединился.");
                MessengerConnection clientHandler = new MessengerConnection(client, "Client " + Count_client_current.ToString(), this);
                clientHandler.Start();
                lock (clients)//лист только для одного потока
                {
                    clients.Add(clientHandler);
                }
                
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
        }

        public void Stop()/////////////////////////////////////////////////////////////////////////////////////////////////////////
        {
            foreach (MessengerConnection client in clients)
            {
                //отключение клиента
                client.Close();
            }
        }


        //удаление клиента
        public void disscon(MessengerConnection s)/////////////////////////////////////////////////////////////////////////////////////////
        {
            Console.WriteLine("Клиент {0} разорвал соединение", s.NAME_cli);
            clients.Remove(s);
            Count_client_real--;
        }



        public void DeliverMessage(byte[] message, int bytesRead, MessengerConnection sender)
        {
            Console.WriteLine("Отправка пакета.");

            if (bytesRead == 66)//запрос на доступ к списку карт
            {
                Load_map_files(sender);
                return;
            }

            if (bytesRead == 55)//запрос на количество клиентов
            {
                XmlSerializer serializer = new XmlSerializer(typeof(int));
                MemoryStream ms = new MemoryStream();
                serializer.Serialize(ms, Count_client_real);
                lock (sender) { }
                sender.ReceiveMessage(ms.ToArray(),(int)ms.Length);
                return;
            }

            if (SaveMap(message, bytesRead, sender) == true)//если пришел запрос на сохранение карты на сервере
            {
                Load_map_files(sender);
            }

            MessengerConnection[] connectedClient;

            lock (clients)
            {
                connectedClient = clients.ToArray();
            }

            foreach (MessengerConnection client in clients)
            {//отправка сообщения клиентам
                try
                {
                    if(client!=sender)
                        client.ReceiveMessage(message, bytesRead);
                }
                catch 
                {
                    //отключение клиента если сообщения прекратились
                    lock (client)
                    {
                        clients.Remove(client);
                    }
                    client.Close();
                }
            }
        }

        bool SaveMap(byte[] buf, int bytesRead, MessengerConnection sender)//сохраняет карту в файл
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(PacketMap));
                MemoryStream ms = new MemoryStream(buf, 0, bytesRead);
                PacketMap message = (PacketMap)serializer.Deserialize(ms);
                if (already_exist(message))
                    return true;
                using (StreamWriter sw = new StreamWriter(message.Name+".tnk"))
                {
                    sw.Write(prepare_map_string(message.wallinfo_array,message.Name));
                }
                increase_map_mas();
                packetmaps[packetmaps.Length -1] = message;                

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
         
        bool already_exist(PacketMap pm)
        {
            foreach (PacketMap p in packetmaps)
            {
                if (p.Name == pm.Name)
                    return true;
            }
            return false;
        }

        void increase_map_mas()
        {
            PacketMap[] new_p = new PacketMap[packetmaps.Length ];
            int i = 0;
            for (i = 0; i < packetmaps.Length; i++)
                new_p[i] = packetmaps[i];
            packetmaps = new PacketMap[new_p.Length + 1];
            for (i = 0; i < new_p.Length; i++)
                 packetmaps[i]=new_p[i] ;
        }

        string prepare_map_string(WallInfo [] ms,string name)//подготовка строки для записи в файл карты
        {
            string s = string.Empty;
            s = name + " " + ms.Length.ToString() + " ";
            foreach (WallInfo w in ms)
            {
                s += w.background + " ";
                s += w.left_up.ToString() + " ";
                s += w.right_down.ToString() + " ";
            }
            return s;
        }

        void Load_map_files(MessengerConnection sender)
        {
            maps = Directory.GetFiles(Environment.CurrentDirectory, "*.tnk");
            packetmaps = new PacketMap[maps.Length];
            int i = 0;
            foreach (string fname in maps)
            {
                using (StreamReader sr = new StreamReader(fname))
                {
                    String line;
                    line = sr.ReadLine();
                    process_map_string(line, i++);
                }
            }

            XmlSerializer serializer = new XmlSerializer(typeof(PacketMap[]));
            //подготовка сообщения
            MemoryStream ms = new MemoryStream();

            //сериалиция объекта PaketTank в поток байтов
            serializer.Serialize(ms, packetmaps);

            byte[] messageData = ms.ToArray();
            lock (sender) { }
            sender.ReceiveMessage(messageData,messageData.Length);

        }

        void process_map_string(string s,int count)//восстанавливает карту из файла
        {
            string[] temp = s.Split(new Char[]{' ','X','=','Y','{','}',','},StringSplitOptions.RemoveEmptyEntries);
            PacketMap pm = new PacketMap();
            pm.Name = temp[0];
            int num = Convert.ToInt32(temp[1]);
            pm.wallinfo_array = new WallInfo[num];
            int i;
            try
            {
                for (i = 0; i < num; i++)
                {
                    WallInfo wi = new WallInfo();
                    wi.background = temp[i * 5 + 2];
                    wi.left_up.X = Convert.ToInt32(temp[i * 5 + 3]);
                    wi.left_up.Y = Convert.ToInt32(temp[i * 5 + 4]);
                    wi.right_down.X = Convert.ToInt32(temp[i * 5 + 5]);
                    wi.right_down.Y = Convert.ToInt32(temp[i * 5 + 6]);
                    pm.wallinfo_array[i] = wi;
                }
                packetmaps[count] = pm;
            }
            catch (Exception ex)
            { }
        }

    }

}

